#include <stdio.h>
#include <iostream>
#include <string>

#include "ServerBootstrap.h"
#include "ReactorThreadPool.h"
#include "Options.h"
#include "Log.h"

using namespace dsth;
using std::string;

class EchoServer {
public:
    EchoServer(EventLoop* loop, const InetSocketAddress& addr)
        :  server_(loop, addr) {
        server_.SetOnConnection(std::make_pair(this, &EchoServer::OnConnect));
        server_.SetOnMessage(std::make_pair(this, &EchoServer::OnMessage));
    }

    EchoServer(ReactorThreadPool* pool, const InetSocketAddress& addr)
        : server_(pool, addr) {
        server_.SetOnConnection(std::make_pair(this, &EchoServer::OnConnect));
        server_.SetOnMessage(std::make_pair(this, &EchoServer::OnMessage));
    }

    void Run() {
        server_.Run();
    }

    void OnConnect(Connection* conn) {
        printf("An new connection\n");
    }

    void OnMessage(Connection* conn, ChannelBuffer* buf, Timestamp time) {
        string msg(buf->FetchAsString());
        printf("RECV:%s\n AT:%s\n\n", msg.c_str(), time.ToFomattedString().c_str());
        conn->Send(msg.c_str(), msg.length());
    }

private:
    ServerBootstrap server_;
};

#ifdef IS_WINDOWS
static void ExitForWindows() {
    printf("::WSACleanup()\n");
    ::WSACleanup();
}
#endif

static void promptForQuit() {
    std::string line;
    while (std::getline(std::cin, line)) {
        if (line[0] == 'q') {
            break;
        }
    }
}

int main(int argc, char** argv) {
    NewLogger("./echo_server.log", Logger::E_DEBUG);
    printf("ChannelBufferLength:%d\nReactorTimeoutUsec:%d\nConnectRetryTime:%d\n",
        GetOption("ChannelBufferLength").intVal,
        GetOption("ReactorTimeoutUsec").intVal,
        GetOption("ConnectRetryTime").intVal);

    SetOption("HostIP", "127.0.0.1");
    unsigned short hostport = 2012;
    SetOption("HostPort", hostport);
    printf("GetHostIP:%s Port:%d", GetOption("HostIP").strVal, GetOption("HostIP").usVal);

    SetOption("ChannelBufferLength", 2046);
    SetOption("ChannelBufferPrepend", 16);
#ifdef IS_WINDOWS
    WSADATA wsaData;
    int err = ::WSAStartup( MAKEWORD(2,2), &wsaData );
    if( err != NO_ERROR )
        printf("Error at WSAStartup\n");
    ::atexit(ExitForWindows);
#endif
    int start_type = 0;
    int thread_num = 1;
    if (argc > 1) {
        start_type = ::atoi(argv[1]);
        if (argc > 2) {
            int num = ::atoi(argv[2]);
            thread_num = (thread_num > num) ? thread_num : num;
        }
    }
    if (start_type == 0) {
        InetSocketAddress addr(2012);
        EventLoop loop;
        EchoServer echo(&loop, addr);
        echo.Run();
        loop.Loop();
    }
    else if (start_type == 1) {
        ReactorThread thread;
        InetSocketAddress addr(2012);
        EchoServer echo(thread.Run(), addr);
        echo.Run();        
        promptForQuit();
    }
    else {
        ReactorThreadPool pool(thread_num);
        InetSocketAddress addr(2012);
        EchoServer echo(&pool, addr);
        echo.Run();
        pool.Run();
        promptForQuit();
    }
    return 0;
}
